package com.wm.blog_admin.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.wm.blog_admin.controller.resp.MenuResp;
import com.wm.blog_admin.dao.*;
import com.wm.blog_admin.query.TMenuQuery;
import com.wm.blog_common.base.BeanUtils;
import com.wm.blog_common.bean.PageHelper;
import com.wm.blog_common.bean.QueryPage;
import com.wm.blog_common.constatnt.ErrorConstant;
import com.wm.blog_common.domain.TMenuDO;
import com.wm.blog_common.entity.*;
import com.wm.blog_common.enums.AdminFlag;
import com.wm.blog_common.enums.DeleteFlag;
import com.wm.blog_common.resp.IviewTreeResp;
import com.wm.blog_common.result.Result;
import com.wm.blog_common.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author wm_yu
 * @since 2020-03-04
 */
@Service
@Slf4j
public class TMenuService{
    @Autowired
    private TMenuDAO tMenuDAO;

    @Autowired
    private TAdminRoleDAO tAdminRoleDAO;

    @Autowired
    private TRoleMenuDAO sysRoleMenuDAO;

    @Autowired
    private TRoleService sysRoleService;

    @Autowired
    private TAdminDAO tAdminDAO;

    @Autowired
    private TButtonPermissionDAO tButtonPermissionDAO;

    /**
     * 根据ID查询
     * @param id
     * @return
     */
    public Result<TMenuDO> selectById(Long id){
        return Result.success(BeanUtils.copyProperties(tMenuDAO.getById(id),TMenuDO.class));
    }

    /**
     * 根据ID删除 菜单
     * @param id
     * @param userId 登录人id
     * @return
     */
    public Result deleteById(Long id,Long userId){
        if(ObjectUtils.isEmpty(id)){
            return Result.failure(ErrorConstant.MENU_ID_EMPTY);
        }
        //TODO 待优化
       /* Result result = this.checkAdmin(userId, id);
        if(!result.isSuccess()){
            return result;
        }*/
        //查询该菜单是否有关联的角色
        QueryWrapper<TRoleMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("menu_id",id);
        queryWrapper.last("limit 1");
        TRoleMenu roleMenu = Optional.ofNullable(sysRoleMenuDAO.getOne(queryWrapper)).orElse(new TRoleMenu());
        if(!ObjectUtils.isEmpty(roleMenu.getId())){
            return Result.failure(ErrorConstant.MENU_ROLE_NO_EMPTY);
        }
        //删除该菜单及其子菜单
        QueryWrapper<TMenu> wrapper = new QueryWrapper<>();
        //必须拥有能
        wrapper.apply(String.format("id = %s or parent_id = %s",id,id));
        return tMenuDAO.remove(wrapper)?Result.success():Result.failure();
    }


    /**
     * 修改 菜单编辑
     * @param sysMenu
     * @return
     */
    public Result update(TMenu sysMenu){
        //校验菜单名称&菜单id
        sysMenu = Optional
                .ofNullable(sysMenu)
                .orElse(new TMenu());
        if(ObjectUtils.isEmpty(sysMenu.getId())){
            return Result.failure("菜单id为空");
        }
        if(StringUtils.isEmpty(sysMenu.getText())){
            return Result.success("菜单名称为空");
        }
        //查询菜单
        TMenu entity = Optional
                .ofNullable(tMenuDAO.getById(sysMenu.getId()))
                .orElse(new TMenu());
        if(ObjectUtils.isEmpty(entity.getId())){
            return Result.failure("菜单不存在");
        }
        //校验是否需要不要参数url
        if(!StringUtils.isEmpty(entity.getUrl()) && StringUtils.isEmpty(sysMenu.getUrl())){
            return Result.failure("编辑url地址不能为空");
        }else{
            entity.setUrl(sysMenu.getUrl());
        }
        entity.setName(sysMenu.getName());
        entity.setColor(sysMenu.getColor());
        entity.setSize(sysMenu.getSize());
        entity.setType(sysMenu.getType());
        entity.setText(sysMenu.getText());
        return tMenuDAO.updateById(entity)?Result.success():Result.failure();
    }

    /**
     * 统计总数
     *
     * @param query
     * @retur
     */
    public Result<Integer> count(TMenuQuery query) {
        return Result.success(tMenuDAO.count(this.combineQuery(query)));
    }

    /**
     * 列表查询
     * @param query
     * @return
     */
    public Result<List<TMenuDO>> list(TMenuQuery query){
        return Result.success(BeanUtils.copyListProperties(tMenuDAO.list(this.combineQuery(query)),TMenuDO.class));
    }
    /**
     * 分页查询
     * @param page
     * @return
     */
    public Result<Page<TMenuDO>> page(QueryPage page, TMenuQuery query){
        query.setSortColumns("sort");
        return Result.success(PageHelper.newPage(tMenuDAO.page(page,this.combineQuery(query)),TMenuDO.class));
    }

    /**
     * 组装查询条件
     *
     * @param query
     * @return
     */
    private QueryWrapper<TMenu> combineQuery(TMenuQuery query) {
        QueryWrapper<TMenu> wrapper = new QueryWrapper<>();
        Optional.ofNullable(query).ifPresent(x -> {
            Optional.ofNullable(query.getUserId()).ifPresent(y -> {
            });
            Optional.ofNullable(query.getParentId()).ifPresent(y -> {
                wrapper.eq("parent_id",y);
            });
            Optional.ofNullable(query.getDelFlag()).ifPresent(y -> {
                wrapper.eq("del_flag",y);
            });
            Optional.ofNullable(query.getId()).ifPresent(y -> {
                wrapper.eq("id",y);
            });
            Optional.ofNullable(query.getStatus()).ifPresent(y -> {
                wrapper.eq("del_flag",y);
            });
            Optional.ofNullable(query.getStartTime()).filter(StringUtil::isNotEmpty).ifPresent(y -> {
                wrapper.apply("DATE(create_date) >= DATE('"+y+"')");
            });
            Optional.ofNullable(query.getEndTime()).filter(StringUtil::isNotEmpty).ifPresent(y -> {
                wrapper.apply("DATE(create_date) <= DATE('"+y+"')");
            });
            Optional.ofNullable(query.getText()).filter(StringUtil::isNotEmpty).ifPresent(y -> {
                wrapper.like("text",y);
            });
            Optional.ofNullable(query.getSortColumns()).filter(org.apache.commons.lang3.StringUtils::isNotEmpty).ifPresent(y -> {
                wrapper.orderByAsc(y);
            });
        });
        return wrapper;
    }

    /**
     * 添加 菜单
     * @param sysMenu
     * @return
     */
    public Result insert(TMenu sysMenu,Long userId){
        sysMenu = Optional.ofNullable(sysMenu).orElse(new TMenu());
        //菜单名称不能为空
        if(StringUtils.isEmpty(sysMenu.getText())){
            return Result.failure("菜单名称不能为空");
        }
        if(ObjectUtils.isEmpty(sysMenu.getParentId())){
            return Result.failure("父级节点的id不能为空");
        }
        if(-1 != sysMenu.getParentId() && StringUtils.isEmpty(sysMenu.getName())){
            //校验name 路由名称
            return Result.failure("跳转路由名称不能为空");
        }
        //查询菜单名称是否重复
        QueryWrapper<TMenu> wrapper = new QueryWrapper<>();
        wrapper.eq("text",sysMenu.getText());
        if(tMenuDAO.count(wrapper) > 0){
            return Result.failure("菜单名称已经存在");
        }
        //根据传入的pid,来查询菜单信息,计算sort字段,在sort末尾追加
        QueryWrapper<TMenu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("parent_id",sysMenu.getParentId());
        queryWrapper.last("order by sort desc limit 1");
        TMenu entity = Optional
                .ofNullable(tMenuDAO.getOne(queryWrapper))
                .orElse(new TMenu());
        //没有同级的菜单,给定order=1 否则追加
        sysMenu.setSort(ObjectUtils.isEmpty(entity.getId()) ? 1:entity.getSort() + 1);
        boolean save = tMenuDAO.save(sysMenu);
        log.info("新增菜单是否成功:[{}]",save);
        //如果新增的菜单,其之前已经有跳转路由,需要将数据库中的跳转路由置为空,否则新增加的菜单不能跳转
        TMenu menu = new TMenu();
        menu.setId(sysMenu.getParentId());
        menu.setName(null);
        boolean b = tMenuDAO.updateById(menu);
        log.info("修改父级菜单的跳转路由是否成功:[{}]",b);
        return Result.success();
    }

    /**
     * 加载当前用户的菜单
     * @param userId
     * @return
     */
    public Result currentMenu(Long userId) {
        if(ObjectUtils.isEmpty(userId) || -1 == userId){
            return Result.failure("用户不能为空/登录过期");
        }
        //查询用户角色,一个用户可能多个角色
        QueryWrapper<TAdminRole> userRoleWrapper = new QueryWrapper<>();
        userRoleWrapper.eq("admin_id",userId);
        List<TAdminRole> userRoleList = Optional
                .ofNullable(tAdminRoleDAO.list(userRoleWrapper))
                .orElse(new ArrayList<>());
        if(!CollectionUtils.isEmpty(userRoleList)){
            //构建角色id
            List<Long> roleIdList = userRoleList
                    .stream()
                    .map(TAdminRole::getRoleId)
                    .distinct()
                    .collect(Collectors.toList());


            //查询角色id下拥有的按钮权限
            List<String> urlList = this.getButtonUrlList(roleIdList);
            MenuResp resp = new MenuResp();
            resp.setButtonUrlList(urlList);
            //查询所拥有的菜单id
            QueryWrapper<TRoleMenu> roleMenuQueryWrapper = new QueryWrapper<>();
            roleMenuQueryWrapper.in("role_id",roleIdList);
            List<Long> menuIdList = Optional
                    .ofNullable(sysRoleMenuDAO.list(roleMenuQueryWrapper))
                    .orElse(new ArrayList<>())
                    .stream()
                    .map(TRoleMenu::getMenuId)
                    .collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(menuIdList)){
                if(!this.checkAccountActive(userId)){
                    menuIdList.clear();
                    //如果账号是未激活状态的,只返回home首页菜单,其他不返回
                    QueryWrapper<TMenu> wrapper = new QueryWrapper<>();
                    wrapper.eq("name","home");
                    wrapper.last("limit 1");
                    Long id = Optional.ofNullable(tMenuDAO.getOne(wrapper)).orElse(new TMenu()).getId();
                    menuIdList.add(id);
                }
                //查询所有的菜单目录
                List<TMenu> menuList = (List<TMenu>) Optional
                        .ofNullable(tMenuDAO.listByIds(menuIdList))
                        .orElse(new ArrayList<>());
                //过滤掉被禁用的菜单
                List<TMenu> resultList = menuList
                        .stream()
                        .filter(x -> DeleteFlag.ENABLE.getValue().equals(x.getDelFlag()))
                        .collect(Collectors.toList());
                //构建菜单树
                List<MenuTree> menuTreeList = MenuUtil.buildDeepTree(resultList);
                resp.setMenuTreeList(menuTreeList);
                return Result.success(resp);
            }
        }
        return Result.success();
    }

    /**
     * 查询所有未被禁用的菜单,构建菜单树,返回iview树形控件格式
     * @return
     */
    public Result allMenuIvTree(Long roleId) {
        TMenuQuery query = new TMenuQuery();
        query.setDelFlag(DeleteFlag.ENABLE.getValue());
        QueryWrapper<TMenu> wrapper = this.combineQuery(query);
        List<TMenu> menuList = Optional.ofNullable(tMenuDAO.list(wrapper)).orElse(new ArrayList<>());
        //菜单树构建
        List<MenuTree> treeList = MenuUtil.buildDeepTree(menuList);
        //iview树形控件构建
        List<IviewTreeResp> respList = new ArrayList<>();
        CommonUtil.buildIvTree(treeList,respList);
        //查询该角色下的权限菜单
        if(!ObjectUtils.isEmpty(roleId)){
            QueryWrapper<TRoleMenu> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("role_id",roleId);
            List<Long> menuIdList = Optional.ofNullable(sysRoleMenuDAO.list(queryWrapper))
                    .orElse(new ArrayList<>())
                    .stream()
                    .map(TRoleMenu::getMenuId)
                    .collect(Collectors.toList());
            if(!CollectionUtils.isEmpty(menuIdList)){
                //挑出需要回显的数据,添加checked为true
                CommonUtil.dealChecked(respList,menuIdList);
            }
        }
        return Result.success(respList);
    }



    public Result checkAdmin(Long userId,Long menuId){
        //查询该账号是否有权限编辑/新增系统菜单
        TMenu menu = Optional.ofNullable(tMenuDAO.getById(menuId)).orElse(new TMenu());
        if(!ObjectUtils.isEmpty(menu.getId()) && AdminFlag.DISABLE.getValue().equals(menu.getIsAdmin())){
            //校验是否当前登录时管理员,否则无权操作
            TAdmin user = Optional.ofNullable(tAdminDAO.getById(userId)).orElse(new TAdmin());
            //todo 权限判定
            /*if(!ObjectUtils.isEmpty(user.getId()) && AdminFlag.DISABLE.getValue().equals(user.getIsAdmin())){
                return Result.failure(ErrorConstant.MENU_NOT_PERMISSION);
            }*/
        }
        return Result.success();
    }

    /**
     * 默认菜单上
     * @param id
     * @param upFlag
     * @return
     */
    public Result moveSort(Long id,Boolean upFlag,Long parentId) {
        if(ObjectUtils.isEmpty(id)){
            return Result.failure(ErrorConstant.MENU_ID_EMPTY);
        }
        if(ObjectUtils.isEmpty(parentId)){
            return Result.failure(ErrorConstant.MENU_PARENT_ID_EMPTY);
        }
        upFlag =  Optional.ofNullable(upFlag).orElse(true);
        Map<String, Object> map = new HashMap<>(5);
        map.put("id",id);
        map.put("upFlag",upFlag);
        map.put("parentId",parentId);
        //菜单上移  查询该菜单id比当前小的最近一条数据
        TMenu menu = Optional.ofNullable(tMenuDAO.nearSortMenu(map)).orElse(new TMenu());
        if(ObjectUtils.isEmpty(menu.getId())){
            return Result.failure(ErrorConstant.MENU_SORT_UNCHANGE);
        }
        //交换两个菜单的排序值
        TMenu sysMenu = Optional.ofNullable(tMenuDAO.getById(id)).orElse(new TMenu());
        int sort = menu.getSort();
        menu.setSort(sysMenu.getSort());
        sysMenu.setSort(sort);
        tMenuDAO.updateById(sysMenu);
        return Result.success(tMenuDAO.updateById(menu));
    }

    public Result getById(Long id) {
        if(ObjectUtils.isEmpty(id)){
            return Result.failure(ErrorConstant.MENU_ID_EMPTY);
        }
        return Result.success(Optional.ofNullable(tMenuDAO.getById(id)).orElse(new TMenu()));
    }

    /**
     * 校验账号是否被激活,已经激活了返回true
     * @return
     */
    public boolean checkAccountActive(Long adminId){
        if(ObjectUtils.isEmpty(adminId)){
            return false;
        }
        TAdmin admin = Optional.ofNullable(tAdminDAO.getById(adminId)).orElse(new TAdmin());
        if(!ObjectUtils.isEmpty(admin.getId()) && DeleteFlag.ENABLE.getValue().equals(admin.getStatus())){
            return true;
        }
        return false;
    }


    private List<String> getButtonUrlList(List<Long> roleIdList){
        if(CollectionUtils.isEmpty(roleIdList)){
            return Collections.emptyList();
        }
        List<String> urlList = new ArrayList<>();
        roleIdList.stream().distinct().forEach(item -> {
            QueryWrapper<TButtonPermission> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("status",DeleteFlag.ENABLE.getValue());
            queryWrapper.apply(String.format("find_in_set(%s,role_id)",item));
            urlList.addAll(Optional
                    .ofNullable(tButtonPermissionDAO.list(queryWrapper))
                    .orElse(Collections.emptyList())
                    .stream()
                    .map(TButtonPermission::getUrl)
                    .collect(Collectors.toList()));
        });
        return urlList;
    }

}


